package services

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"github.com/prometheus/common/model"
	"github.com/spf13/viper"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/request"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/response"
	"go.didapinche.com/foundation/plat-echo/app/ops/repositories"
	"go.didapinche.com/foundation/plat-echo/pkg/constants"
	promentheus "go.didapinche.com/foundation/plat-echo/pkg/prometheus"
	data2 "go.didapinche.com/foundation/plat-echo/pkg/utils/data"
	"go.didapinche.com/foundation/plat-echo/pkg/utils/structs"
	time2 "go.didapinche.com/time"
	"go.uber.org/zap"
	"sort"
	"strconv"
	"strings"
	"time"
)

type GraphService interface {
	Create(ctx context.Context, graph *models.Graph) (*models.Graph, error)
	Update(ctx context.Context, graph *models.Graph) (*models.Graph, error)
	Delete(ctx context.Context, id uint64) error
	FindByID(ctx context.Context, id uint64) (*models.Graph, error)
	FindGraphByAppID(ctx context.Context, appID uint64, userID string) (*response.GraphInfo, error)
	UpdateGraphPosition(ctx context.Context, ID uint64, position *models.GraphPosition) error
	Subscribe(ctx context.Context, graphID uint64, uid string, status bool, subType int) error
	FindGraphByAHostIP(ctx context.Context, IP string) ([]*response.GraphType, error)
	FindGraphByApi(ctx context.Context, id uint64) (*response.GraphInfo, error)
	FindByDashboardID(ctx context.Context, ID uint64, uid string) ([]*response.GraphType, *models.Dashboard, error)
	UpdateGraphType(ctx context.Context, ID uint64, req *request.GraphTypeReq) error
	UpdateSilence(ctx context.Context, ID uint64, silence *models.Silence) error

	GetGraphData(ctx context.Context, param *request.GraphDataReq) ([]map[string]interface{}, map[string]map[string]interface{}, float64, float64, int, error)

	//清理api重复数据
	ClearApiK8s(ctx context.Context) error
}
type graphService struct {
	repository             repositories.GraphRepository
	logger                 *zap.Logger
	k8s                    K8sService
	apiRepository          repositories.ApiRepository
	appRepository          repositories.ApplicationRepository
	dashboardRepository    repositories.DashboardRepository
	templateRepository     repositories.TemplateRepository
	hostRepository         repositories.HostRepository
	prometheus             *promentheus.PrometheusService
	alertRepository        repositories.AlertCurrentRepository
	alertHistoryRepository repositories.AlertHistoryRepository
}

func NewGraphService(repository repositories.GraphRepository,
	k8s K8sService,
	alertHistoryRepository repositories.AlertHistoryRepository,
	alertRepository repositories.AlertCurrentRepository,
	prometheus *promentheus.PrometheusService,
	dashboardRepository repositories.DashboardRepository,
	apiRepository repositories.ApiRepository,
	templateRepository repositories.TemplateRepository,
	appRepository repositories.ApplicationRepository,
	hostRepository repositories.HostRepository,
	logger *zap.Logger) GraphService {
	return &graphService{
		repository:             repository,
		appRepository:          appRepository,
		alertHistoryRepository: alertHistoryRepository,
		apiRepository:          apiRepository,
		alertRepository:        alertRepository,
		dashboardRepository:    dashboardRepository,
		hostRepository:         hostRepository,
		k8s:                    k8s,
		templateRepository:     templateRepository,
		prometheus:             prometheus,
		logger:                 logger.With(zap.String("type", "services.graphService")),
	}
}

//
func (s *graphService) Create(ctx context.Context, graph *models.Graph) (*models.Graph, error) {
	if graph.AppID != 0 {
		graph.Kind = 0
		app, err := s.appRepository.FindByID(ctx, graph.AppID)
		if err != nil {
			s.logger.Error("call appRepository FindByID error", zap.Error(err))
			return nil, errors.Wrap(err, "call appRepository FindByID error")
		}
		//app只有自定义可能创建模版
		graph.TypeID = constants.TemplateCustom
		graph.Level = app.Level
	} else if graph.ApiID != 0 {
		graph.Kind = 1
		api, err := s.apiRepository.FindByID(ctx, graph.AppID)
		if err != nil {
			s.logger.Error("call apiRepository FindByID error", zap.Error(err))
			return nil, errors.Wrap(err, "call apiRepository FindByID error")
		}
		graph.Level = api.Level
	} else if graph.DashboardID != 0 {
		graph.Kind = 3
	}
	graph, err := s.repository.Create(ctx, graph)
	if err != nil {
		s.logger.Error("call GraphRepository Create error", zap.Error(err))
		return nil, errors.Wrap(err, "call GraphRepository Create error")
	}
	// 同步k8s
	if err := s.UpdateK8s(ctx, graph); err != nil {
		s.logger.Error("call GraphRepository UpdateK8s error", zap.Error(err))
	}
	return graph, nil
}

func (s *graphService) Update(ctx context.Context, graph *models.Graph) (*models.Graph, error) {
	graph2, err := s.repository.FindByID(ctx, graph.ID)
	if err != nil {
		s.logger.Error("call GraphRepository Save error", zap.Error(err))
		return nil, err
	}
	graph.Kind = graph2.Kind
	graph.TypeID = graph2.TypeID
	graph.Order = graph2.Order
	graph.IsForce = graph2.IsForce
	graph.TemplateId = graph2.TemplateId
	graph.ApiID = graph2.ApiID
	graph.AppID = graph2.AppID
	graph.DashboardID = graph2.DashboardID
	graph.HostID = graph2.HostID
	if graph.Kind == 0 || graph.Kind == 1 {
		template, err := s.templateRepository.FindByNameAndKind(ctx, graph.Name, int(graph.Kind))
		if err == nil {
			graph.TemplateId = template.ID
		}
	}
	graph, err = s.repository.Save(ctx, graph)
	if err != nil {
		s.logger.Error("call GraphRepository Save error", zap.Error(err))
		return nil, err
	}
	if err := s.UpdateK8s(ctx, graph); err != nil {
		s.logger.Error("call GraphRepository UpdateK8s error", zap.Error(err))
	}
	if err := s.alertRepository.Delete(ctx, graph.ID); err != nil {
		s.logger.Error("call alertRepository Delete error", zap.Error(err))
	}
	return graph, nil
}

func (s *graphService) Delete(ctx context.Context, id uint64) error {
	graph, err := s.repository.FindByID(ctx, id)
	if err != nil {
		s.logger.Error("call GraphRepository Save error", zap.Error(err))
	}
	if err := s.repository.Delete(ctx, id); err != nil {
		s.logger.Error("call GraphRepository Save error", zap.Error(err))
	}
	if err := s.UpdateK8s(ctx, graph); err != nil {
		s.logger.Error("call GraphRepository UpdateK8s error", zap.Error(err))
	}
	return nil
}

//name是规则名，可以用appName，apiID，dashboardName，ip表示
func (s *graphService) UpdateK8s(ctx context.Context, graph *models.Graph) error {
	id := 0
	name := ""
	if graph.Kind == 0 {
		app, err := s.appRepository.FindByID(ctx, graph.AppID)
		if err != nil {
			s.logger.Error("call appRepository.FindByID error", zap.Error(err))
			return errors.Wrap(err, "call appRepository.FindByID error")
		}
		id = int(app.ID)
		name = app.Name
	} else if graph.Kind == 1 {
		return nil
		//id = int(graph.ApiID)
		//name = "api-" + strconv.Itoa(int(graph.ApiID))
	} else if graph.Kind == 2 {
		//host, err := s.hostRepository.FindByID(ctx, graph.AppID)
		//if err != nil {
		//	s.logger.Error("call hostRepository.FindByID error", zap.Error(err))
		//	return errors.Wrap(err, "call hostRepository.FindByID error")
		//}
		//id = int(host.ID)
		//name = host.IP
		return nil
	} else if graph.Kind == 3 {
		dashboard, err := s.dashboardRepository.FindByID(ctx, graph.DashboardID)
		if err != nil {
			s.logger.Error("call hostRepository.FindByID error", zap.Error(err))
			return errors.Wrap(err, "call hostRepository.FindByID error")
		}
		id = int(dashboard.ID)
		name = "dashboard-" + dashboard.Name
	}
	graphs, err := s.repository.FindByKindAndID(ctx, id, int(graph.Kind))
	if err != nil {
		s.logger.Error("call GraphRepository FindByKindAndID error", zap.Error(err))
		return errors.Wrap(err, "call GraphRepository FindByKindAndID error")
	}
	s.k8s.UpdateAlertResource(ctx, name, graphs)
	return nil
}

func (s *graphService) FindGraphByAppID(ctx context.Context, appID uint64, userID string) (*response.GraphInfo, error) {
	var isOwner bool
	app, err := s.appRepository.FindByID(ctx, appID)
	if err != nil {
		s.logger.Error("call appRepository FindByID error", zap.Error(err))
		return nil, errors.Wrap(err, "call appRepository FindByID error")
	}
	for _, a := range app.GetOwners() {
		if a.UserID == userID {
			isOwner = true
		}
	}
	graphs, err := s.repository.FindGraphByAppID(ctx, appID)
	if err != nil {
		s.logger.Error("call GraphRepository FindGraphByAppID error", zap.Error(err))
		return nil, errors.Wrap(err, "call GraphRepository FindGraphByAppID error")
	}
	m1 := make(map[uint64][]*response.Graph)
	m2 := make(map[uint64]*response.Graph)
	for _, g := range graphs {
		// 过滤golang，java报警
		if g.TypeID == constants.Java && app.Language != "java" {
			continue
		}
		if g.TypeID == constants.Go && app.Language != "go" {
			continue
		}

		g.UserID = userID
		g.IsOwner = isOwner
		m2[g.TypeID] = response.NewGraph(g)
		if _, ok := m1[g.TypeID]; ok {
			m1[g.TypeID] = append(m1[g.TypeID], response.NewGraph(g))
		} else {
			graphs2 := make([]*response.Graph, 0)
			graphs2 = append(graphs2, response.NewGraph(g))
			m1[g.TypeID] = graphs2
		}
	}
	graphInfo := new(response.GraphInfo)
	isCustom := false
	for k, v := range m1 {
		graphType := new(response.GraphType)
		graphType.Name = m2[k].TypeName
		graphType.Key = m2[k].Key
		graphType.Order = m2[k].Order2
		graphType.Id = m2[k].TypeID
		if "DEFAULT" == strings.ToUpper(graphType.Name) {
			graphType.DefaultExpand = true
		}
		if "" == strings.ToUpper(graphType.Name) || graphType.Id == 0 {
			graphType.Name = "自定义"
		}
		if graphType.Name == "自定义" {
			isCustom = true
		}
		sort.Sort(response.GraphSlice(v))
		graphType.Types = v
		graphInfo.GraphType = append(graphInfo.GraphType, graphType)
	}
	if !isCustom {
		graphType := new(response.GraphType)
		graphType.Order = 0
		graphType.Name = "Custom"
		graphType.Key = "custom"
		graphType.Id = 0
		graphInfo.GraphType = append(graphInfo.GraphType, graphType)
	}
	sort.Sort(response.GraphTypeSlice(graphInfo.GraphType))
	graphInfo.App = app
	return graphInfo, nil
}

func (s *graphService) FindByID(ctx context.Context, id uint64) (*models.Graph, error) {
	graph, err := s.repository.FindByID(ctx, id)
	if err != nil {
		s.logger.Error("call appRepository FindByID", zap.Error(err))
		return nil, errors.Wrap(err, "call appRepository FindByID")
	}

	//
	if graph.Kind == 0 {
		graph.Kind2 = "app-template"
		app, err := s.appRepository.FindByID(ctx, graph.AppID)
		if err == nil {
			graph.AppName = app.Name
			graph.AppID = app.ID
		}
	} else if graph.Kind == 1 {
		api, err := s.apiRepository.FindByID(ctx, graph.ApiID)
		if err == nil {
			if api.HttpPath != "" {
				api.TemplateType = 1
			} else {
				api.TemplateType = 2
			}
			graph.AppID = api.AppID
			graph.AppName = api.AppName
			graph.ApiInfo = api
			if api.Type == 2 {
				api2, err := s.apiRepository.FindByZeusServer(ctx, api.ZeusMethod, api.ZeusService)
				if err == nil {
					graph.ApiInfo.ParentApiID = api2.ID
				}
			}
		}
		graph.Kind2 = "api-template"
	} else if graph.Kind == 3 {
		graph.Kind2 = "dashboard"
	}
	if graph.TypeID == constants.TemplateCustom {
		graph.Kind2 = "custom"
	}
	return graph, err
}

func (s *graphService) GetGraphData(ctx context.Context, param *request.GraphDataReq) ([]map[string]interface{}, map[string]map[string]interface{}, float64, float64, int, error) {
	timeStepStr := param.TimeStep
	timeStep := int64(2) //判断图表时间间隔
	var err error

	if timeStepStr != "" {
		timeStep, err = strconv.ParseInt(timeStepStr, 10, 64)
		if err != nil {
			timeStep = 15
		}
	}
	start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
	if err != nil {
		return nil, nil, 0, 0, 0, err
	}
	end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
	if err != nil {
		return nil, nil, 0, 0, 0, err
	}
	// 指定图表数据从apollo中获得，默认为100个，可以修改
	num := viper.GetInt64("graph.num")
	if num == 0 {
		num = 100
	}
	timeStep = (end.Unix() - start.Unix()) / num
	if timeStep <= 0 {
		timeStep = 30
	}
	// 尝试查询图信息，如果是echo应用，会存在该信息，非echo调用无此信息
	graphPanel, err := s.repository.FindByID(ctx, param.GraphID)
	var threshold float64
	if err == nil {
		if graphPanel.General != nil {
			param.Decimals = graphPanel.General.Yaxes.Decimals
		}
		if graphPanel.Alert != nil {
			threshold2, err := strconv.ParseFloat(graphPanel.Alert.Threshold, 64)
			if err == nil {
				threshold = threshold2
			}
		}
	} else {
		param.Decimals = 2
	}
	legendFormat := data2.FormatLegend(param.LegendFormat)
	linkFormat := data2.FormatLegend(param.LinkFormat)
	var state = 0

	date, err := promentheus.NewDate(param.Start, param.End, 0, timeStep)
	if err != nil {
		return nil, nil, 0, 0, 0, errors.Wrap(err, "time is invalid")
	}
	datas, err := s.prometheus.QueryRangeProm(param.Expression, date)
	if err != nil {
		return nil, nil, 0, 0, 0, errors.Wrap(err, "prometheus QueryRangeProm error")
	}
	var result []map[string]interface{}
	statMap := make(map[string]*response.MetricStat)
	switch datas.(type) {
	case model.Matrix:
		{
			if matrix, ok := datas.(model.Matrix); ok {
				if matrix.Len() == 0 {
					return nil, nil, 0, 0, 0, nil
				}
				if matrix.Len() > 0 {
					max := 0
					for i, _ := range matrix {
						if len(matrix[i].Values) > max {
							max = len(matrix[i].Values)
						}
					}
					result = make([]map[string]interface{}, max)
					for i, _ := range result {
						result[i] = make(map[string]interface{})
					}
				}
				for _, mat := range matrix {
					key := ""
					for _, l := range legendFormat {
						if key != "" {
							key += " " + string(mat.Metric[model.LabelName(l)])
						} else {
							key += string(mat.Metric[model.LabelName(l)])
						}
					}
					if key == "" {
						key = mat.Metric.String()
					}
					link := param.LinkFormat
					for _, l := range linkFormat {
						link = strings.ReplaceAll(link, "{{."+l+"}}", string(mat.Metric[model.LabelName(l)]))
					}
					for i, v := range mat.Values {
						if v.Value.String() == "NaN" {
							v.Value = 0
						}
						value, _ := strconv.ParseFloat(fmt.Sprintf("%."+strconv.Itoa(param.Decimals)+"f", float64(v.Value)), 64)

						if i == len(mat.Values) {
							if value < threshold && threshold != 0 {
								state = 1
							}
						}

						result[i][key] = value
						result[i]["time"] = time2.Time{v.Timestamp.Time()}
						if metricStat, ok := statMap[key]; ok {
							metricStat.Link = link
							metricStat.Total += value
							metricStat.Current = value
							metricStat.Avg, _ = strconv.ParseFloat(fmt.Sprintf("%."+strconv.Itoa(param.Decimals)+"f", float64(metricStat.Total/float64(i+1))), 64)
							if value > metricStat.Max {
								metricStat.Max = value
							}
							if value < metricStat.Min {
								metricStat.Min = value
							}
							statMap[key] = metricStat
						} else {
							metricStat := new(response.MetricStat)
							metricStat.Total += value
							metricStat.Current = value
							metricStat.Avg, _ = strconv.ParseFloat(fmt.Sprintf("%."+strconv.Itoa(param.Decimals)+"f", float64(metricStat.Total/float64(i+1))), 64)
							metricStat.Max = value
							metricStat.Max = value
							statMap[key] = metricStat
						}

					}

				}
			}
		}
	default:
	}

	stat := map[string]map[string]interface{}{}
	var limit float64 = 0
	var min float64 = 0
	if graphPanel != nil {
		visualization := graphPanel.Visualization
		if visualization.Options.ShowLegend || (visualization.Type == models.Table && len(visualization.Table.Data.Columns) > 0) {
			var legend []string
			if visualization.Type == models.Table {
				legend = visualization.Table.Data.Columns
			} else if visualization.Type == models.GaugeType {
				legend = []string{visualization.Gauge.Calc}
			} else {
				legend = visualization.Values
			}
			for key, metricStat := range statMap {
				m := structs.Map(&metricStat)
				if !data2.ContainString(legend, response.MIN) {
					delete(m, response.MIN)
				}
				if !data2.ContainString(legend, response.MAX) {
					delete(m, response.MAX)
				}
				if !data2.ContainString(legend, response.TOTAL) {
					delete(m, response.TOTAL)
				}
				if !data2.ContainString(legend, response.AVG) {
					delete(m, response.AVG)
				}
				if !data2.ContainString(legend, response.CURRENT) {
					delete(m, response.CURRENT)
				}
				if metricStat.Max > limit {
					limit = metricStat.Max
				}
				if metricStat.Min < min {
					min = metricStat.Min
				}
				stat[key] = m
			}
		}
	} else {
		for key, metricStat := range statMap {
			m := structs.Map(&metricStat)
			if metricStat.Max > limit {
				limit = metricStat.Max
			}
			if metricStat.Min < min {
				min = metricStat.Min
			}
			stat[key] = m
		}
	}

	if graphPanel != nil && graphPanel.Alert != nil && len(graphPanel.Alert.Threshold) > 0 {
		v, err := strconv.ParseFloat(graphPanel.Alert.Threshold, 64)
		if err == nil {
			if v > limit {
				limit = v
			}
			if v < min {
				min = v
			}
		}
	}
	return result, stat, limit, min, state, nil
}

func (s *graphService) UpdateGraphPosition(ctx context.Context, ID uint64, position *models.GraphPosition) error {
	graph, err := s.repository.FindByID(ctx, ID)
	if err != nil {
		return err
	}
	graph.Visualization.Position = *position
	_, err = s.repository.Save(ctx, graph)
	if err != nil {
		return err
	}
	return nil
}

func (s *graphService) Subscribe(ctx context.Context, graphID uint64, uid string, status bool, subType int) error {
	graph, err := s.repository.FindByID(ctx, graphID)
	if err != nil {
		return err
	}
	isOwner := s.isOwner(ctx, uid, graph)
	if status {
		// 订阅
		if graph.Subscribe == nil {
			graph.Subscribe = new(models.Subscribe)
		}
		if subType == 0 {
			graph.Subscribe.Phones = append(graph.Subscribe.Phones, uid)
		} else {
			graph.Subscribe.Sms = append(graph.Subscribe.Sms, uid)
		}

	} else {
		// 取消订阅
		if graph.Subscribe == nil {
			return nil
		}
		if subType == 0 {
			if graph.IsForce && isOwner && data2.ContainInt(graph.Subscribe.SubscribeForce, 0) {
				return errors.New("强制订阅，无法修改")
			}
			for i, _ := range graph.Subscribe.Phones {
				if graph.Subscribe.Phones[i] == uid {
					graph.Subscribe.Phones = append(graph.Subscribe.Phones[:i], graph.Subscribe.Phones[i+1:]...)
				}
			}

		} else {
			if graph.IsForce && isOwner && data2.ContainInt(graph.Subscribe.SubscribeForce, 0) {
				return errors.New("强制订阅，无法修改")
			}
			for i, _ := range graph.Subscribe.Sms {
				if graph.Subscribe.Sms[i] == uid {
					graph.Subscribe.Sms = append(graph.Subscribe.Sms[:i], graph.Subscribe.Sms[i+1:]...)
				}
			}
		}
	}
	_, err = s.repository.Save(ctx, graph)
	if err != nil {
		return err
	}
	return nil
}

//判断是否是owner
func (s *graphService) isOwner(ctx context.Context, uid string, graph *models.Graph) bool {
	if graph.Kind == 0 {
		app, err := s.appRepository.FindByID(ctx, graph.AppID)
		if err != nil {
			return false
		}
		for _, u := range app.GetOwners() {
			if u.UserID == uid {
				return true
			}
		}
	} else if graph.Kind == 1 {
		api, err := s.apiRepository.FindByID(ctx, graph.ApiID)
		if err != nil {
			return false
		}
		for _, u := range api.GetOwners() {
			if u.UserID == uid {
				return true
			}
		}
	}
	return false
}

func (s *graphService) FindGraphByAHostIP(ctx context.Context, IP string) ([]*response.GraphType, error) {
	host, err := s.hostRepository.FindByIP(ctx, IP)
	if err != nil {
		s.logger.Error("call hostRepository FindByIP error", zap.Error(err))
		return nil, errors.Wrap(err, "call hostRepository FindByIP error")
	}
	graphs, err := s.repository.FindGraphByHostID(ctx, host.ID)
	if err != nil {
		s.logger.Error("call GraphRepository FindGraphByAppID error", zap.Error(err))
		return nil, errors.Wrap(err, "call GraphRepository FindGraphByAppID error")
	}
	m1 := make(map[uint64][]*response.Graph)
	m2 := make(map[uint64]*response.Graph)
	for _, g := range graphs {
		m2[g.TypeID] = response.NewGraph(g)
		if _, ok := m1[g.TypeID]; ok {
			m1[g.TypeID] = append(m1[g.TypeID], response.NewGraph(g))
		} else {
			graphs2 := make([]*response.Graph, 0)
			graphs2 = append(graphs2, response.NewGraph(g))
			m1[g.TypeID] = graphs2
		}
	}
	graphInfo := new(response.GraphInfo)
	for k, v := range m1 {
		graphType := new(response.GraphType)
		graphType.Name = m2[k].TypeName
		graphType.Key = m2[k].Key
		graphType.Order = m2[k].Order2
		graphType.Id = m2[k].TypeID
		if "DEFAULT" == strings.ToUpper(graphType.Name) {
			graphType.DefaultExpand = true
		}
		graphs2 := make([]*response.Graph, 0)
		graphsMap := make(map[string]*response.Graph)
		for _, g := range v {
			graphsMap[g.Name] = g
		}
		for _, g := range graphsMap {
			graphs2 = append(graphs2, g)
		}
		sort.Sort(response.GraphSlice(graphs2))
		graphType.Types = graphs2
		graphInfo.GraphType = append(graphInfo.GraphType, graphType)
	}
	sort.Sort(response.GraphTypeSlice(graphInfo.GraphType))
	return graphInfo.GraphType, nil
}

func (s *graphService) FindGraphByApi(ctx context.Context, id uint64) (*response.GraphInfo, error) {
	api, err := s.apiRepository.FindByID(ctx, id)
	if err != nil {
		s.logger.Error("call apiRepository FindByID error", zap.Error(err))
		return nil, errors.Wrap(err, "call apiRepository FindByID error")
	}
	graphs, err := s.repository.FindGraphByApiID(ctx, api.ID)
	if err != nil {
		s.logger.Error("call GraphRepository FindGraphByApiID error", zap.Error(err))
		return nil, errors.Wrap(err, "call GraphRepository FindGraphByApiID error")
	}

	m1 := make(map[uint64][]*response.Graph)
	m2 := make(map[uint64]*response.Graph)
	for _, g := range graphs {
		g.Status = 1
		if api.DisableGraph != nil && len(api.DisableGraph.GraphID) > 0 {
			if data2.ContainInt(api.DisableGraph.GraphID, int(g.ID)) {
				g.Status = 0
			}
		}
		if api.Type == 0 && (g.TypeID == constants.ZeusServerTempType || g.TypeID == constants.ZeusClientTempType) {
			continue
		}
		if api.Type == 1 && (g.TypeID == constants.ApiHttpTempType || g.TypeID == constants.ZeusClientTempType) {
			continue
		}
		if api.Type == 2 && (g.TypeID == constants.ApiHttpTempType || g.TypeID == constants.ZeusServerTempType) {
			continue
		}
		m2[g.TypeID] = response.NewGraph(g)
		if _, ok := m1[g.TypeID]; ok {
			if api.DisableGraph != nil {
				if data2.ContainInt(api.DisableGraph.GraphID, int(g.ID)) {
					continue
				}
			}
			m1[g.TypeID] = append(m1[g.TypeID], response.NewGraph(g))
		} else {
			if api.DisableGraph != nil {
				if data2.ContainInt(api.DisableGraph.GraphID, int(g.ID)) {
					continue
				}
			}
			graphs2 := make([]*response.Graph, 0)
			graphs2 = append(graphs2, response.NewGraph(g))
			m1[g.TypeID] = graphs2
		}

	}
	graphInfo := new(response.GraphInfo)
	for k, v := range m1 {
		graphType := new(response.GraphType)
		graphType.Name = m2[k].TypeName
		graphType.Key = m2[k].Key
		graphType.Order = m2[k].Order2
		graphType.Id = m2[k].TypeID
		if "DEFAULT" == strings.ToUpper(graphType.Name) {
			graphType.DefaultExpand = true
		}
		sort.Sort(response.GraphSlice(v))
		graphType.Types = v
		graphInfo.GraphType = append(graphInfo.GraphType, graphType)
	}
	sort.Sort(response.GraphTypeSlice(graphInfo.GraphType))
	graphInfo.Api = api
	return graphInfo, nil
}
func (s *graphService) FindByDashboardID(ctx context.Context, ID uint64, uid string) ([]*response.GraphType, *models.Dashboard, error) {
	dashboard, err := s.dashboardRepository.FindByID(ctx, ID)
	if err != nil {
		s.logger.Error("call dashboardRepository FindByID error", zap.Error(err))
		return nil, nil, errors.Wrap(err, "call hostRepository FindByIP error")
	}
	dashboards, err := s.dashboardRepository.FindByParentID(ctx, ID)
	if err != nil {
		s.logger.Error("call dashboardRepository FindByParentID error", zap.Error(err))
		return nil, nil, errors.Wrap(err, "call hostRepository FindByParentID error")
	}
	ids := make([]uint64, 0)
	ids = append(ids, ID)
	m1 := make(map[uint64][]*response.Graph)
	graphTypes := make([]*response.GraphType, 0)
	graphType := new(response.GraphType)
	graphType.Name = "Default"
	graphType.Key = strconv.Itoa(int(dashboard.ID))
	graphType.DefaultExpand = dashboard.Expand
	graphType.Id = dashboard.ID
	graphTypes = append(graphTypes, graphType)
	for _, d := range dashboards {
		ids = append(ids, d.ID)
		graphType := new(response.GraphType)
		graphType.Name = d.Name
		graphType.Key = strconv.Itoa(int(d.ID))
		graphType.DefaultExpand = d.Expand
		graphType.Id = d.ID
		graphTypes = append(graphTypes, graphType)
	}
	graphs, err := s.repository.FindGraphByDashboardID(ctx, ids)
	if err != nil {
		s.logger.Error("call dashboardRepository FindByID error", zap.Error(err))
		return nil, nil, errors.Wrap(err, "call dashboardRepository FindByID error")
	}
	for _, g := range graphs {
		if _, ok := m1[g.TypeID]; ok {
			m1[g.TypeID] = append(m1[g.TypeID], response.NewGraph(g))
		} else {
			graphs2 := make([]*response.Graph, 0)
			graphs2 = append(graphs2, response.NewGraph(g))
			m1[g.TypeID] = graphs2
		}
	}
	graphInfo := new(response.GraphInfo)
	for _, g := range graphTypes {
		if v, ok := m1[g.Id]; ok {
			sort.Sort(response.GraphSlice(v))
			g.Types = v
		}
		graphInfo.GraphType = append(graphInfo.GraphType, g)
	}
	return graphInfo.GraphType, dashboard, nil
}

func (s *graphService) UpdateGraphType(ctx context.Context, ID uint64, req *request.GraphTypeReq) error {
	graph, err := s.repository.FindByID(ctx, ID)
	if err != nil {
		return err
	}
	graph.DashboardID = req.DashboardID
	_, err = s.repository.Save(ctx, graph)
	if err != nil {
		return err
	}
	return nil
}

func (g *graphService) UpdateSilence(ctx context.Context, ID uint64, silence *models.Silence) error {
	graphPanel, err := g.repository.FindByID(ctx, ID)

	duration, err := time.ParseDuration(silence.Duration)
	if err != nil {
		return errors.Wrap(err, "param duration error")
	}
	now := time.Now()
	silence.StartTime = time2.Time{now}
	silence.EndTime = time2.Time{now.Add(duration)}

	graphPanel.Silence = silence

	_, err = g.repository.Save(ctx, graphPanel)
	if err != nil {
		return errors.Wrap(err, "update graph error")
	}

	return nil
}

func (g graphService) ClearApiK8s(ctx context.Context) error {
	apis, err := g.apiRepository.FindRepeat(ctx)
	if err != nil {
		return err
	}
	for _, api := range apis {
		name := "api-" + strconv.Itoa(int(api.ID))
		g.k8s.DeleteAlertResource(ctx, name)
	}
	return nil
}
